/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   AIN模块  
  Function List:     
  History:
    <wangmc -- 2014-12-15>  创建
    <wyg -- 2023-02-24>  重构
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "audioPriv.h"

/*=============================================================================
                               Macro Definition
 =============================================================================*/

/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/

/*=============================================================================
                             Extern Variables                                  
=============================================================================*/
extern unsigned long long vdo_get_time();

static uint8 airplayBuffer[MAX_PCM_SIZE] = {0};
static uint8 airplayRefBuf[MAX_PCM_SIZE] = {0};
static uint airplayLen = 0;
static uint airplayRefLen = 0;

/*=============================================================================
                             Local Variables                                  
 =============================================================================*/


/*=============================================================================
                             Function Definition                                  
 =============================================================================*/
/*******************************************************************************
    Function:     AI_DoResampler
    Description:  音频数据重采样
    Input:        - pAiCtl: 音频编码通道控制结构体指针
                  - inputData：音频源数据
                  - inputLen：音频源数据长度
    Output:       - outputData：音频重采样后的数据
                  - outputLen：音频重采样后的长度
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
*******************************************************************************/
static int AI_DoResampler(AI_ctl_t* pAiCtl, char *inputData, uint *inputLen, char *outputData, uint *outputLen)
{
    if(!pAiCtl || !inputData || !outputData)
    {
        LOG_PrintError("Input params error\n");
        return -1;
    }
    
    char procBuf[MAX_PCM_SIZE] = {0};
    uint procLen = 0;
    
    int channels = pAiCtl->aiChnAttr.u32Channels;
    uint dealLen = *inputLen;
    for(uint j = 0; j < (*inputLen)/dealLen; ++j)
    {                
        memset(procBuf, 0, sizeof(procBuf)/sizeof(char));
        
        if (2 == channels)
        {
            //双声道变单声道
            for(int i = 0; i < dealLen/2; i+=2)
            {
                procBuf[i] = inputData[dealLen * j + 2 * i];
                procBuf[i + 1] = inputData[dealLen * j + 2 * i + 1];
            }
            procLen = dealLen/2;
            procLen /= 2;
        }
        else if (1 == channels)
        {
            memcpy(procBuf, inputData + dealLen * j , dealLen);
            procLen = dealLen;
            procLen /= 2;
        }
        else
        {
            usleep(5 * 1000);
            LOG_PrintWarn("channels: %d is not support!\n", channels);
            continue;
        }

        if((pAiCtl->resampler) 
          && (pAiCtl->aiChnAttr.u32SampleRate != AUDIO_RESAMPLER_BASE))
        {
            *outputLen = pAiCtl->nbSamples;
            
            speex_resampler_process_int(pAiCtl->resampler, 0, (short*)procBuf, &procLen, (short*)outputData, outputLen);

            *outputLen = (*outputLen) * 2;  
  
        }
        else
        {
            *outputLen = 2 * procLen;
            memcpy(outputData, procBuf, *outputLen);
        }
    }

    return 0;
}

/*******************************************************************************
    Function:     AI_AirplayResample
    Description:  音频数据重采样
    Input:        - pComposeCtl:混音控制结构体指针
                  - pAiCtl: 音频编码通道控制结构体指针
                  - inLen：音频源数据
                  - inputLen：音频源数据长度
    Output:       - outBuf：音频重采样后的数据
                  - outLen：音频重采样后的长度
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
*******************************************************************************/
static int AI_AirplayResample(AMIX_composeCtl_t* pComposeCtl, AI_ctl_t* pAiCtl, char *pInData, uint inLen, char *outBuf, uint outLen)
{
    char procBuf[MAX_PCM_SIZE] = {0};
    uint procLen = 0;
    uint dealLen = inLen;
    int channels = pAiCtl->aiChnAttr.u32Channels;

    if(2 == channels)
    {
        for(int i = 0; i < dealLen/2; i+=2)
        {
            procBuf[i] = pInData[2 * i];
            procBuf[i + 1] = pInData[2 * i + 1];
        }
    }

    memcpy(airplayBuffer + airplayLen, procBuf, dealLen / 2);
    airplayLen += dealLen / 2;
    
    if(pAiCtl->resampler) 
    {  
        while(airplayLen >= AUDIO_RESAMPLE_10MS_16BIT_44100HZ){
            procLen = AUDIO_RESAMPLE_10MS_44100HZ;
            outLen = AUDIO_RESAMPLER_TIME_44100_BASE;

            memset(airplayRefBuf + airplayRefLen, 0, outLen * 2);
            //LOG_PrintInfo("procLen1111:%d  outputLen:%d dealLen:%d \n", procLen, *outputLen, dealLen);
            speex_resampler_process_int(pAiCtl->resampler, 0, (short*)(airplayBuffer), &procLen, (short*)(airplayRefBuf + airplayRefLen), &outLen);
            
            if(outLen == AUDIO_RESAMPLER_TIME_44100_BASE){
                airplayRefLen += outLen * 2;
                memmove(airplayBuffer, airplayBuffer + procLen * 2, airplayLen - procLen * 2);
                airplayLen -= procLen * 2;
            }
            else
            {
                memmove(airplayBuffer, airplayBuffer + procLen * 2, airplayLen - procLen * 2);
                airplayLen -= procLen * 2;
                return -1;
            }
        }

        while(airplayRefLen >= AUDIO_RESAMPLE_OUT_TO_LIST_LEN)
        {
            uint64 pts = vdo_get_time();
            outLen = AUDIO_RESAMPLE_OUT_TO_LIST_LEN;
            memset(outBuf, 0, outLen);
            memcpy(outBuf, airplayRefBuf, outLen);

            memmove(airplayRefBuf, airplayRefBuf + outLen, airplayRefLen - outLen);
            airplayRefLen -= outLen;

            ACOMM_listInfo_t* pListFrame = NULL; 
            pthread_mutex_lock(&pAiCtl->aiBufLock);
            if(!list_empty(&pAiCtl->emptyBuf))
            {
                pListFrame = list_first_entry(&pAiCtl->emptyBuf, ACOMM_listInfo_t, list);
                list_del(&pListFrame->list);
                pthread_mutex_unlock(&pAiCtl->aiBufLock);
                
                pListFrame->len = outLen;
                pListFrame->pts = pts;                        
                if((pListFrame->pts <= pAiCtl->lastPts) && (pAiCtl->lastPts > 0))
                {
                    pListFrame->pts = pAiCtl->lastPts + 1;
                }
                pAiCtl->lastPts = pListFrame->pts;

                memset(pListFrame->pBuf, 0, pAiCtl->maxBufLen);        
                memcpy(pListFrame->pBuf, outBuf, pListFrame->len);               

                pthread_mutex_lock(&pAiCtl->aiBufLock);
                list_add_tail(&pListFrame->list, &pAiCtl->fullBuf);
                pthread_mutex_unlock(&pAiCtl->aiBufLock);
                pComposeCtl->newPts[pAiCtl->aiChn] = pListFrame->pts; //更新buf时间
            }
            else
            {
                pthread_mutex_unlock(&pAiCtl->aiBufLock);
                if((pts <= pAiCtl->lastPts) && (pAiCtl->lastPts > 0))
                {
                pts = pAiCtl->lastPts + 1;
                }
                pAiCtl->lastPts = pts;
                pComposeCtl->newPts[pAiCtl->aiChn] = pts; //更新buf时间
                return -1;
            }
        }
    }

    return 0;
}

/*******************************************************************************
    Function:     AI_PutPacketToList
    Description:  从外部输入音频数据
    Input:        - pThiz: 音频输入接口指针
    Output:       - packet：输入的音频数据指针
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
*******************************************************************************/
static int AI_PutPacketToList(struct AudioInput *pThiz, AudioInPacket *packet) 
{
    int ret = 0;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    AI_ctl_t* pAiCtl = (AI_ctl_t *)pThiz->priv;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }

    AMIX_composeCtl_t* pComposeCtl = audioCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return -1;
    }

    uint64 pts = vdo_get_time();

    ///resampler data
    uint inLen = packet->length;
    char *pInData = packet->buffer;
    char outBuf[MAX_PCM_SIZE] = {0};
    uint outLen = 0;

    if(pAiCtl->aiChnAttr.u32SampleRate != AUDIO_RESAMPLE_44100HZ)
    {
        AI_DoResampler(pAiCtl, pInData, &inLen, outBuf, &outLen);
    }
    else
    {
        return AI_AirplayResample(pComposeCtl, pAiCtl, pInData, inLen, outBuf, outLen);
    }

#if 0
    char path[64];
    sprintf(path,"wyg/audio_in_48_%d.pcm",pAiCtl->aiChn);
    if(pAiCtl->aiChn == 1)
    audio_FILE_Write(path, outBuf, outLen); 
    else
    audio_FILE_Write2(path, outBuf, outLen); 
#endif

    ///put empty node from list and full node to list
    ACOMM_listInfo_t* pListFrame = NULL; 
    pthread_mutex_lock(&pAiCtl->aiBufLock);
    if(!list_empty(&pAiCtl->emptyBuf))
    {
        pListFrame = list_first_entry(&pAiCtl->emptyBuf, ACOMM_listInfo_t, list);
        list_del(&pListFrame->list);
        pthread_mutex_unlock(&pAiCtl->aiBufLock);

        pListFrame->len = outLen;
        pListFrame->pts = pts;                        
        if((pListFrame->pts <= pAiCtl->lastPts) && (pAiCtl->lastPts > 0))
        {
            pListFrame->pts = pAiCtl->lastPts + 1;

            //LOG_PrintInfo("AI_PutPacketToList::pAiCtl->lastPts=%llu, pts=%llu\n", pAiCtl->lastPts, pListFrame->pts);
        }
        pAiCtl->lastPts = pListFrame->pts;

        //LOG_PrintInfo("AI_PutPacketToList3::pAiCtl->lastPts=%llu, pts=%llu\n", pAiCtl->lastPts, pListFrame->pts);

        memset(pListFrame->pBuf, 0, pAiCtl->maxBufLen);        
        memcpy(pListFrame->pBuf, outBuf, pListFrame->len);               

        pthread_mutex_lock(&pAiCtl->aiBufLock);
        list_add_tail(&pListFrame->list, &pAiCtl->fullBuf);
        pthread_mutex_unlock(&pAiCtl->aiBufLock);

        pComposeCtl->newPts[pAiCtl->aiChn] = pListFrame->pts; //更新buf时间

        
    }
    else
    {
        pthread_mutex_unlock(&pAiCtl->aiBufLock);
        if((pts <= pAiCtl->lastPts) && (pAiCtl->lastPts > 0))
        {
           pts = pAiCtl->lastPts + 1;
        }
        pAiCtl->lastPts = pts;
        pComposeCtl->newPts[pAiCtl->aiChn] = pts; //更新buf时间
        //LOG_PrintWarn("emptyBuf list is empty!\n");
        ret = -1;
    }

    return ret;
}

/*******************************************************************************
    Function:     AI_GetFullFromList
    Description:  从full对列取数据
    Input:        - pThiz: 音频输入接口指针
    Output:       - pListPacket：获取队列的节点数据指针
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
  *******************************************************************************/
int AI_GetFullFromList(AI_ctl_t *pAiCtl, ACOMM_listInfo_t* pListPacket) 
{
    int ret = 0;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }

    ACOMM_listInfo_t* pListFrame = NULL; 

    ///get full node from list
    pthread_mutex_lock(&pAiCtl->aiBufLock);            
    if(!list_empty(&pAiCtl->fullBuf))
    {
        pListFrame = list_first_entry(&pAiCtl->fullBuf, ACOMM_listInfo_t, list);
        list_del(&pListFrame->list);

        memcpy(pListPacket, pListFrame,sizeof(ACOMM_listInfo_t)); //浅拷贝
        pListPacket->revered = pListFrame; //记录指针后续返还
        pthread_mutex_unlock(&pAiCtl->aiBufLock);

        //printf("AI_GetFullFromList:: bufLen=%d\n",pListFrame->len);
    }
    else
    {
        pthread_mutex_unlock(&pAiCtl->aiBufLock);

        //LOG_PrintError("AI_GetFullFromList fullBuf is NULL\n");
        ret = -1;
    }

    return ret;
}

 /*******************************************************************************
    Function:     AI_PutEmptyToList
    Description:  将节点放回empty队列
    Input:        - pThiz: 音频输入接口指针
                  - pListPacket：放回队列的节点数据指针
    Output:       无
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
  *******************************************************************************/
int AI_PutEmptyToList(AI_ctl_t *pAiCtl, ACOMM_listInfo_t* pListPacket) 
{
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }    

    ACOMM_listInfo_t* pListFrame = (ACOMM_listInfo_t*)pListPacket->revered; 

    ///put empty node to list
    pthread_mutex_lock(&pAiCtl->aiBufLock); 
    list_add_tail(&pListFrame->list, &pAiCtl->emptyBuf);
    pthread_mutex_unlock(&pAiCtl->aiBufLock);
    
    return 0;
}

 /*******************************************************************************
   Function:     AI_DeinitList
   Description:  情况队列
   Input:        - pAiCtl: 音频编码通道控制结构体指针
   Output:       无
   Return:       0: 操作成功
                 -1: 操作失败
   Others:       无
 *******************************************************************************/
 static int AI_DeinitList(AI_ctl_t *pAiCtl)
 {
     ACOMM_listInfo_t *pListFrame;
 
     pthread_mutex_lock(&pAiCtl->aiBufLock);
     
     while (!list_empty(&pAiCtl->fullBuf))
     {
         pListFrame = list_first_entry(&pAiCtl->fullBuf, ACOMM_listInfo_t, list);
         list_del(&pListFrame->list);
         list_add_tail(&pListFrame->list, &pAiCtl->emptyBuf);
     }
 
     pthread_mutex_unlock(&pAiCtl->aiBufLock);
 
     LOG_PrintError("AI_DeinitList SUCCESS\n");
             
     return 0;
 }


 /*******************************************************************************
   Function:     AI_PacketCb
   Description:  音频数据回调函数
   Input:        无
   Output:       - mb：回调数据的BUF指针
   Return:       0: 操作成功
                 -1: 操作失败
   Others:       无
 *******************************************************************************/
 static void AI_PacketCb(MEDIA_BUFFER mb) 
 {
    AI_ctl_t *pAiCtl;
    ACOMM_listInfo_t *pListFrame;
    unsigned short chnId;

    AMIX_composeCtl_t* pComposeCtl = audioCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        goto release_buf;
    }

    chnId = RK_MPI_MB_GetChannelID(mb);

    pAiCtl = audioCtl_g.pAiCtls[chnId];
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        goto release_buf;
    }

    ///考虑到linein数据刚启动数据异常，采取丢第一帧采集的数据
    if(pAiCtl->discardFlg == 1)
    {
        pAiCtl->discardFlg = 0;
        goto release_buf;
    }

    uint64 pts = vdo_get_time();

    if (RK_MPI_MB_GetModeID(mb) == RK_ID_AI) 
    {
        if (chnId >= AUDIO_LOGICIN_MAX)
        {
            LOG_PrintError("chnId(%d) is invalid.\n", chnId);
            goto release_buf;
        }

#if 1
        ///resampler data
        uint inLen = RK_MPI_MB_GetSize(mb);
        char *pInData = (char*)RK_MPI_MB_GetPtr(mb);
        char outBuf[MAX_PCM_SIZE] = {0};
        uint outLen = 0;

        //audio_FILE_Write("/nfsroot/wyg/Linein1-1.pcm", pInData, inLen);

        AI_DoResampler(pAiCtl, pInData, &inLen, outBuf, &outLen);
#else
        uint outLen = RK_MPI_MB_GetSize(mb);
        char *outBuf = (char*)RK_MPI_MB_GetPtr(mb);
#endif

        //audio_FILE_Write2("/nfsroot/wyg/Linein1-2.pcm", outBuf, outLen);

        pthread_mutex_lock(&pAiCtl->aiBufLock);
        if(!list_empty(&pAiCtl->emptyBuf))
        {
            pListFrame = list_first_entry(&pAiCtl->emptyBuf, ACOMM_listInfo_t, list);
            list_del(&pListFrame->list);
            pthread_mutex_unlock(&pAiCtl->aiBufLock);
           
            pListFrame->len = outLen;
            pListFrame->pts = pts; //RK_MPI_MB_GetTimestamp(mb);
            if((pListFrame->pts <= pAiCtl->lastPts) && (pAiCtl->lastPts > 0))
            {
                pListFrame->pts = pAiCtl->lastPts + 1;
            }
            pAiCtl->lastPts = pListFrame->pts;

            memset(pListFrame->pBuf, 0, pAiCtl->maxBufLen);
            memcpy(pListFrame->pBuf, outBuf, outLen);

            //LOG_PrintInfo("AI_PacketCb:: aiChn:%d, bufLen=%d, pts=%llu, pListFrame->pts=%llu, runtime=%llu\n",pAiCtl->aiChn, pListFrame->len, pts, pListFrame->pts, (pListFrame->pts - pts));

            pthread_mutex_lock(&pAiCtl->aiBufLock);
            list_add_tail(&pListFrame->list, &pAiCtl->fullBuf);
            pthread_mutex_unlock(&pAiCtl->aiBufLock);

            pComposeCtl->newPts[pAiCtl->aiChn] = pListFrame->pts; //更新buf时间
        }
        else
        {
            pthread_mutex_unlock(&pAiCtl->aiBufLock);
            if((pts <= pAiCtl->lastPts) && (pAiCtl->lastPts > 0))
            {
               pts = pAiCtl->lastPts + 1;
            }
            pAiCtl->lastPts = pts;
            pComposeCtl->newPts[pAiCtl->aiChn] = pts; //更新buf时间            
            //LOG_PrintWarn("AI_PacketCb emptyBuf list is empty!\n");
        }       
    }

    if(pAiCtl->aiSource == LINE_IN_TYPE)
    {
        pComposeCtl->decComposeLen[pAiCtl->aiChn]++;
    }
	
    if(pAiCtl->aiSource == LINE_IN_TYPE && pComposeCtl->decComposeLen[pAiCtl->aiChn] >= 2)
    {
        for(int i = 0; i < MAX_CHN_NUM_AMIX; i++){
            pthread_mutex_lock(&audioCtl_g.mutex_ai[i]);
            audioCtl_g.sharedData_ai[i] = 1;
            pthread_mutex_unlock(&audioCtl_g.mutex_ai[i]);
        }

        pthread_cond_broadcast(&audioCtl_g.cond_ai);
        pComposeCtl->decComposeLen[pAiCtl->aiChn]--;
    }
release_buf:
    RK_MPI_MB_ReleaseBuffer(mb);

    return ;
}


/*******************************************************************************
  Function:     AI_AddRef
  Description:  增加接口引用
  Input:        - pThiz: 音频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AI_AddRef(struct AudioInput *pThiz)
{
    AI_ctl_t *pAiCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAiCtl = (AI_ctl_t *)pThiz->priv;
    if (!pAiCtl)
    {
        LOG_PrintError("VideoEncoder isn't initialized\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aiMutex);

    pAiCtl->refCount++;
    
    pthread_mutex_unlock(&audioCtl_g.aiMutex);
    
    return 0;
}

/*******************************************************************************
  Function:     AI_Release
  Description:  释放接口
  Input:        - pThiz: 音频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AI_Release(struct AudioInput *pThiz)
{
    int ret = 0;
    AI_ctl_t *pAiCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAiCtl = (AI_ctl_t *)pThiz->priv;
    if (!pAiCtl)
    {
        LOG_PrintError("VideoEncoder isn't initialized\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aiMutex);

    if (pAiCtl->refCount > 1)
    {
        pAiCtl->refCount--;
        goto unlock_mutex;
    }

    pAiCtl->refCount--;

    audioCtl_g.pAiCtls[pAiCtl->aiChn] = NULL;
    free(pAiCtl);  
    
unlock_mutex:       
    pthread_mutex_unlock(&audioCtl_g.aiMutex);
    return ret;
}

/*******************************************************************************
  Function:     AI_SetAudioInAttr
  Description:  设置AudioIn通道属性
  Input:        - pThiz: 音频输入接口指针
                - aiAttr：通道属性
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AI_SetAudioInAttr(struct AudioInput *pThiz, AudioInAttr aiAttr)
{
    int ret = 0;
    AI_ctl_t *pAiCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAiCtl = (AI_ctl_t *)pThiz->priv;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }

    if( pAiCtl->aiChnState == AI_STREAM_START)
    {
		LOG_PrintWarn("AI chn %d have been start!\n", pAiCtl->aiChn);
		return -1;
	}
    
    pthread_mutex_lock(&audioCtl_g.aiMutex);

    ///清空队列
	AI_DeinitList(pAiCtl);

    ///配置resample参数
     if(pAiCtl->aiChnAttr.u32SampleRate != aiAttr.u32SampleRate)
     {    
         if(pAiCtl->resampler)
         {
             speex_resampler_destroy(pAiCtl->resampler);
         }
         
         pAiCtl->resampler = speex_resampler_init(1, aiAttr.u32SampleRate, AUDIO_RESAMPLER_BASE, 1, NULL);
         if(!pAiCtl->resampler)
         {
             ret = -1;
             goto unlock_mutex;            
         }
         
         speex_resampler_set_rate(pAiCtl->resampler, aiAttr.u32SampleRate, AUDIO_RESAMPLER_BASE);
         speex_resampler_skip_zeros(pAiCtl->resampler); 

         AUDIO_GetOutSamples(AUDIO_RESAMPLER_BASE, &pAiCtl->nbSamples);
     }

     AUDIO_GetResamplerLen(aiAttr.u32SampleRate, 16, aiAttr.u32Channels, &pAiCtl->resamplerLen);

    AI_CHN_ATTR_S* aiChnAttr = &pAiCtl->aiChnAttr;
    strcpy(pAiCtl->aiChnAttr.pcAudioNode, aiAttr.pcAudioNode);   
    aiChnAttr->enSampleFormat = aiAttr.enSampleFormat;
    aiChnAttr->u32Channels = aiAttr.u32Channels;
    aiChnAttr->u32SampleRate = aiAttr.u32SampleRate;
    aiChnAttr->u32NbSamples = aiAttr.u32NbSamples;
    aiChnAttr->enAiLayout = aiAttr.enAiLayout;

    pAiCtl->aiSource = aiAttr.source;

    LOG_PrintInfo("AI_SetAudioInAttr::aiChn:%d, node=%s,u32Channels=%d,u32NbSamples=%d,u32SampleRate=%d, resamplerLen=%d,aiSource=%d\n",
	    pAiCtl->aiChn, pAiCtl->aiChnAttr.pcAudioNode ,pAiCtl->aiChnAttr.u32Channels, pAiCtl->aiChnAttr.u32NbSamples,
	    pAiCtl->aiChnAttr.u32SampleRate,pAiCtl->resamplerLen, pAiCtl->aiSource);

	
 unlock_mutex:       
    pthread_mutex_unlock(&audioCtl_g.aiMutex);   
    
    return ret;
}

/*******************************************************************************
  Function:     AI_StartUnlock
  Description:  启动AudioIn通道
  Input:        - pAiCtl: 音频输入控制指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AI_StartUnlock(AI_ctl_t *pAiCtl)
{
    int ret = 0;
    MPP_CHN_S stEncChn = {0};

    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }

    if(pAiCtl->aiSource == NONE_IN_TYPE)
    {
		LOG_PrintWarn("AI chn %d ,please setChnAttr first!\n", pAiCtl->aiChn);
		return 0;
	}

    if((pAiCtl->aiChnState == AI_STREAM_START) || (pAiCtl->aiSource == EXTERNAL_IN_TYPE))
    {
		LOG_PrintWarn("AI chn %d have been start!\n", pAiCtl->aiChn);
		return 0;
	}

	if(pAiCtl->aiSource == MIC_IN_TYPE)
	{
	    LOG_PrintWarn("pAiCtl->aiSource is MIC_IN_TYPE\n");
        //注意mic需要vo这路同时开启，为了设置i2s频率*****
        AO_CHN_ATTR_S ao_attr = {0};
        ao_attr.pcAudioNode = "plughw:0,0";
    	ao_attr.enSampleFormat = RK_SAMPLE_FMT_S16;
    	ao_attr.u32NbSamples = pAiCtl->aiChnAttr.u32NbSamples;
    	ao_attr.u32SampleRate = pAiCtl->aiChnAttr.u32SampleRate;
    	ao_attr.u32Channels = pAiCtl->aiChnAttr.u32Channels;
        ret = RK_MPI_AO_SetChnAttr(pAiCtl->aiChn, &ao_attr);
    	if (ret)
    	{
    		LOG_PrintError("AO etChnAttr err:%d\n", ret);
    		return -1;
    	}

    	ret = RK_MPI_AO_EnableChn(pAiCtl->aiChn);
    	if (ret)
    	{
    		LOG_PrintError("AO enable err:%d\n", ret);
    		return -1;
    	}
	}


	printf("AI_StartUnlock::aiChn=%d, node=%s,u32Channels=%d,u32NbSamples=%d,u32SampleRate=%d\n",
	    pAiCtl->aiChn,pAiCtl->aiChnAttr.pcAudioNode ,pAiCtl->aiChnAttr.u32Channels, pAiCtl->aiChnAttr.u32NbSamples,pAiCtl->aiChnAttr.u32SampleRate);

    ret = RK_MPI_AI_SetChnAttr(pAiCtl->aiChn, &pAiCtl->aiChnAttr);
	if (ret)
	{
		LOG_PrintError("SetChnAttr err:%d\n", ret);
		return -1;
	}

	//LOG_PrintInfo("AI_StartUnlock RK_MPI_AI_SetChnAttr success\n");
	
		
	ret = RK_MPI_AI_EnableChn(pAiCtl->aiChn);
	if (ret)
	{
		LOG_PrintError("RK_MPI_AI_EnableChn pAiCtl->aiChn:%d, err:%d\n", pAiCtl->aiChn, ret);
		return -1;
	}

	//LOG_PrintInfo("AI_StartUnlock RK_MPI_AI_EnableChn pAiCtl->aiChn:%d success\n", pAiCtl->aiChn);
#if 1

    ///CALLBACK
    stEncChn.enModId = RK_ID_AI;
    stEncChn.s32DevId = 0;
    stEncChn.s32ChnId = pAiCtl->aiChn;
    ret = RK_MPI_SYS_RegisterOutCb(&stEncChn, AI_PacketCb);
    if (ret) 
    {
        LOG_PrintError("Fail to RK_MPI_SYS_RegisterOutCbret=%d\n", ret);
        return -1;
    }

	ret = RK_MPI_AI_StartStream(pAiCtl->aiChn);
	if (ret) 
	{
	    LOG_PrintError("Start AI failed! ret=%d\n", ret);
	    return -1;
	}

	pAiCtl->discardFlg = 1;

	pAiCtl->aiChnState = AI_STREAM_START;
#endif  
    return ret;
}


/*******************************************************************************
  Function:     AI_Start
  Description:  启动AudioIn通道
  Input:        - pThiz: 音频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AI_Start(struct AudioInput *pThiz)
{
    int ret = 0;
    int result = 0;
    AI_ctl_t *pAiCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAiCtl = (AI_ctl_t *)pThiz->priv;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aiMutex);

    result = AI_StartUnlock(pAiCtl);
    if (result)
    {
        LOG_PrintError("Fail to start channel %d!\n", pAiCtl->aiChn);
        ret = -1;
        goto mutex_unlock;
    }

    LOG_PrintInfo("AudioInStart aiChn:%d success\n",pAiCtl->aiChn);

mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.aiMutex);
    
    return ret;
}

/*******************************************************************************
  Function:     AI_StopUnlock
  Description:  停止AudioIn通道
  Input:        - pThiz: 音频输入控制指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int AI_StopUnlock(AI_ctl_t *pAiCtl)
{
    int ret = 0;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }

    if(pAiCtl->aiSource != EXTERNAL_IN_TYPE)
    {
        if( (pAiCtl->aiChnState == AI_STREAM_STOP) )
        {
            LOG_PrintWarn("AI chn %d have been stoped!\n", pAiCtl->aiChn);
            return 0;
        }

        ret = RK_MPI_AI_DisableChn(pAiCtl->aiChn);
        if (ret)
        {
            LOG_PrintError("RK_MPI_AI_DisableChn err:%d\n", ret);
            return -1;
        }
    }

    ///清空队列
	AI_DeinitList(pAiCtl);

	pAiCtl->aiChnState = AI_STREAM_STOP; 

	pAiCtl->discardFlg = 0;
    
    return ret;
}

/*******************************************************************************
  Function:     AI_Stop
  Description:  停止AudioIn通道
  Input:        - pThiz: 音频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int AI_Stop(struct AudioInput *pThiz)
{
    int ret = 0;
    int result = 0;
    AI_ctl_t *pAiCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pAiCtl = (AI_ctl_t *)pThiz->priv;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }
    
    pthread_mutex_lock(&audioCtl_g.aiMutex);

    result = AI_StopUnlock(pAiCtl);
    if (result)
    {
        LOG_PrintError("Fail to start channel %d!\n", pAiCtl->aiChn);
        ret = -1;
        goto mutex_unlock;
    }

    LOG_PrintInfo("AudioInStop aiChn:%d success\n",pAiCtl->aiChn);

mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.aiMutex);
    
    return ret;
}

/*static void* AudioLineInThd(void *parg)
{
    AI_ctl_t *pAiCtl = (AI_ctl_t *)parg;
    if (!pAiCtl)
    {
        LOG_PrintError("pAiCtl is NULL\n");
        return -1;
    }

    MEDIA_BUFFER pstAudioData = NULL;
    int ret = 0;

    while(1)
    {
        if(pAiCtl->aiChnState == AI_STREAM_STOP)
        {
            usleep(100*1000);
            continue;
        }
        
        pstAudioData = RK_MPI_SYS_GetMediaBuffer(RK_ID_AI, pAiCtl->aiChn, -1);
        if (!pstAudioData)
    	{
    	   ret = -1;
    	   continue;
    	}

    	int len = RK_MPI_MB_GetSize(pstAudioData);

    	LOG_PrintInfo("FILE_write len:%d\n", len);
    
        FILE_write("/nfsroot/StreamFile/222.pcm", RK_MPI_MB_GetPtr(pstAudioData), len);
    	
        
	}

    
    return NULL;
    
}
*/

/*******************************************************************************
  Function:     getAudioInputChannels
  Description:  得到音频输入通道的个数
  Input:        无
  Output:       无
  Return:       音频输入通道的个数
  Others:       无
*******************************************************************************/
int PAL_API getAudioInputChannels(void)
{   
	return AUDIO_LOGICIN_MAX;
}

/*******************************************************************************
  Function:     createAudioInput
  Description:  创建音频输入接口
  Input:        - pAiDesc: 音频输入接口描述结构指针
  Output:       - ppAudioInput: 音频输入接口指针的指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int PAL_API createAudioInput(AudioInDesc *pAiDesc, AudioInput **ppAudioInput)
{
    int ret = 0;
    AudioInput *pAudioInput;
    AI_ctl_t *pAiCtl;
    unsigned int channel = 0;

    if ((NULL == pAiDesc) || (NULL == ppAudioInput))
    {
        LOG_PrintError("Parameter is NULL!\n");
        return -1;
    }
   
    channel = pAiDesc->channel;
    if (channel >= AUDIO_LOGICIN_MAX)
    {
        LOG_PrintError("Audio input Channel (%d) is out of range!\n", 
                       channel);
        return -1;
    }

    pthread_mutex_lock(&audioCtl_g.aiMutex);
    
    pAiCtl = audioCtl_g.pAiCtls[channel];
    if (pAiCtl)
    {
        LOG_PrintInfo("audio input Channel (%d) has already been created\n", channel);
        pAiCtl->refCount++;
        *ppAudioInput = &pAiCtl->audioInput;
        goto mutex_unlock;
    }

    pAiCtl = (AI_ctl_t *)malloc(sizeof(AI_ctl_t));
    if (!pAiCtl)
    {
        LOG_PrintError("There is no enough memory to allocate!\n");
        ret = -1;
        goto mutex_unlock;
    }
    memset(pAiCtl, 0, sizeof(AI_ctl_t));
    
    pAiCtl->refCount++;
    pAiCtl->aiChn = channel;
    pAiCtl->aiSource = NONE_IN_TYPE;
    pAiCtl->aiChnAttr.pcAudioNode = (RK_CHAR *)malloc(32 * sizeof(RK_CHAR));
    pAiCtl->discardFlg = 0;
    pAiCtl->lastPts = 0;

    ///init list
    int i;
    INIT_LIST_HEAD(&pAiCtl->emptyBuf);
    INIT_LIST_HEAD(&pAiCtl->fullBuf);
    pthread_mutex_init(&pAiCtl->aiBufLock, NULL);
    pAiCtl->maxBufLen = 8*4096*sizeof(char); //长度待定
    for (i = 0; i < 16; i++)
    {
        pAiCtl->listBuf[i].pBuf = (char *)malloc(pAiCtl->maxBufLen); 
        if (!pAiCtl->listBuf[i].pBuf)
        {
            LOG_PrintError("Fail to malloc!\n");
            ret = -1;
            goto free_ctl;
        }
        pAiCtl->listBuf[i].pts = 0;
        pAiCtl->listBuf[i].len = 0;
	    list_add_tail(&pAiCtl->listBuf[i].list, &pAiCtl->emptyBuf);
	}
    

    audioCtl_g.pAiCtls[channel] = pAiCtl;

    pAudioInput                             = &pAiCtl->audioInput;
    pAudioInput->priv                       = pAiCtl;
    pAudioInput->addRef                     = AI_AddRef;
    pAudioInput->release                    = AI_Release;
    pAudioInput->setChnAttr                 = AI_SetAudioInAttr;
    pAudioInput->start                      = AI_Start;
    pAudioInput->stop                       = AI_Stop;
    pAudioInput->putPacket                  = AI_PutPacketToList; 

    *ppAudioInput = &pAiCtl->audioInput;
    
    LOG_PrintInfo("Create aiChn:%d successfully!\n", pAiCtl->aiChn);


    /*pthread_t audioLineThd;
    ret = pthread_create(&audioLineThd, 0, AudioLineInThd, pAiCtl);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        return -1;
    }*/

    goto mutex_unlock;

free_ctl: 
    free(pAiCtl);
    
mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.aiMutex);
    return ret;
}
